Skip to content

Physical R_* checks of an experiment description (Stage 1, PR 8) - #192

Merged
guijacquemet merged 3 commits into
mainfrom
claude/description-physical
Nov 7, 2026
Merged

guijacquemet merged 3 commits into
mainfrom
claude/description-physical

Conversation

@guijacquemet

@guijacquemet guijacquemet commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Stacked on #190 (claude/discovery-header-additions, which adds the raw header channel names this PR compares). The base is that branch so the diff shows only this PR. Retarget to main after #190 merges. #188 is already merged into that branch.

What

Stage 1 design PR 8 (conformance P01-P03, P10, P12, P13, P23, and the comparison part of P26). Additive: no run, notebook or CLI command uses it yet, and nothing is written.

New module physical_check: check_physical(description, discovery, metadata, excluded=, roles=, mask_types=) returns a PhysicalReport.

  • R_UNIT_NOT_FOUND (declared unit, no included image; P12) and R_UNIT_NOT_DECLARED. Units are matched by source folder labels, never by IDs.
  • R_UNIT_NOT_HOMOGENEOUS (P01, P02): channel count, image type, interpreted axes or raw header name at a C index differ within a unit. The issue names the FOV, path and C index, and no per-FOV exception exists. It replaces R_CHANNEL_COUNT_MISMATCH and R_HEADER_CONTRADICTION for its unit.
  • R_CHANNEL_COUNT_MISMATCH: a whole unit with another count than its declared channel list.
  • R_HEADER_CONTRADICTION (P03, P26): raw name at Ci against the confirmed header_names of the channel at i. NFC of both sides, no trimming, no case folding, no similarity. Unnamed images need no evidence.
  • R_IMAGE_TYPE_CONTRADICTS_HEADER (P13, P23): declared rgb or absent against the header's colour interpretation, in both directions. Pixels are never read, so P23(c) passes with no inference. OME-Zarr states no colour interpretation, so it cannot contradict and is recorded image_type_verified = False.
  • R_MASK_TYPE_NOT_DECLARED (P10): only when the discovered mask types are passed. A declared mask with no files is valid. No mask representation is defaulted or read (Q5).
  • layout_groups (Q3): units with an identical layout are grouped. Only a group whose channels are all header-named is batch_confirmable. Unnamed or partly named layouts need one confirmation per acquisition.
  • Q7: homogeneity compares the axes with T left out, so time-lapses of different lengths, or one time point with no T axis, are one layout.
  • Undecidable images are listed in unchecked, never passed: unreadable headers, and a channel count the header does not state (a plain stack) when no confirmed roles are given.

Choices not fixed by the Spec text (please check)

  • An image type that contradicts the header also replaces the count and header-name checks of that unit. P23(a) and (b) expect only R_IMAGE_TYPE_CONTRADICTS_HEADER.
  • Units declared rgb skip the header-name check, since R, G and B take no aliases (4.4b) and a name could never be confirmed.
  • A unit whose images are partly named and partly unnamed is R_UNIT_NOT_HOMOGENEOUS (the literal "header names at one C index differ"). The Spec text on whether unnamed images count as differing is silent.
  • Only T is left out of the axes comparison, as decided. Z is not: a unit mixing a stack with a single plane differs in axes and is reported. Decided by the owner (2026-11-07): a unit mixing Z-stacks with single planes stays "not homogeneous". No change needed.
  • Not in this PR (other design rows): R_HETEROGENEOUS_LAYOUT_NOT_ENABLED and the mask-pixel check (PR 11), R_FOLDER_NOT_NFC and R_MASK_TYPE_NAME_INVALID (Discovery and header additions for the experiment description (Stage 1, PR 6) #190), N35 reopening (PR 9), and the plain-language texts.

Tests

tests/test_physical_check.py, 23 tests, built on the vendored fixtures v01, v07, v11, v12, v28 and v31. They write real TIFFs and change one image or declaration. On the base branch (#190) the file fails at collection (ModuleNotFoundError: morphobricks_preprocessing.physical_check). Here: 23 passed.

python tools/check.py: 3863 passed, 4 skipped, code rules clean. The 4 skips are environment ones (case-insensitive file system and file-mode tests, unrelated to this change).


Generated by Claude Code

check_physical compares a description with the folder and the image headers: units found and
declared, per-unit homogeneity (replacing the count and header checks of its unit), header
evidence on raw names, image type against the header, and declared mask types. Pixels are
never read; undecidable images are listed as unchecked. layout_groups marks which layouts can
be confirmed once (header-named only).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Scma6W3LC11s3qjXHZuGDm
Base automatically changed from claude/discovery-header-additions to main November 7, 2026 14:36
Python 3.11 refuses an unhashable mappingproxy as a dataclass default, so
tests/test_physical_check.py failed at collection on every 3.11 CI leg.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Scma6W3LC11s3qjXHZuGDm
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Scma6W3LC11s3qjXHZuGDm

# Conflicts:
#	AGENTS.md
#	CHANGELOG.md
@guijacquemet
guijacquemet merged commit 9fc6876 into main Nov 7, 2026
7 checks passed
@guijacquemet
guijacquemet deleted the claude/description-physical branch November 7, 2026 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants